using System;
using System.Collections;
using System.Data;
using System.Reflection;
using Spring.Util;

namespace Sedna.Core.Common.Objects.Navigation
{
	/// <summary>
	/// Represents parsed indexer node in the navigation expression.
	/// </summary>
	[Serializable]
	internal class IndexerNode : NavigationNode
	{
		private object index = null;

		/// <summary>
		/// Index may be null, i.e. node expression may be "[]". This is used for
		/// <see cref="IList"/> population. When index is not specified, <code>SetValue()</code> 
		/// method uses <code>IList.Add(value)</code> instead of <code>IList[index]=value</code>.
		/// Any  subsequent invocation of <code>SetValue()</code> or <code>GetValue()</code> 
		/// will affect value with the same index.
		/// </summary>
		public IndexerNode(NavigationNode parent, string nodeExpression, Type nodeType) : base(parent, nodeExpression, nodeType)
		{
			string tmp = StringUtils.StripFirstAndLastCharacter(nodeExpression).Trim();
			
			if (tmp.Length==0) return; 

			if (tmp[0] == '\'')
			{
				index = StringUtils.StripFirstAndLastCharacter(tmp);
			}
			else
			{
				index = Int32.Parse(tmp);
			}
		}

		protected override object GetValueRecursive(bool autoCreate)
		{
			if (index==null)
			{
				//Every invocation of GetValue(true) causes new object to be created if index is null.
				return null;
			}

			object context=parent.GetValue(autoCreate);
			if (context is IList)
			{
				return ((IList) context)[(int) index];
			}
			else if (context is IDictionary)
			{
				return ((IDictionary) context)[index];
			}
		    else if (context is DataRow)
		    {
                return (index is string) ? ((DataRow)context)[(string)index] : ((DataRow)context)[(int)index];   
		    }
			return null;
		}

		/// <summary>
		/// Sets node's value for the given context.
		/// </summary>
		/// <param name="newValue">New value for this node.</param>
		protected override void SetValue(object newValue)
		{
			object context=parent.GetValue(true);
			IList list=context as IList;
			if (list!=null)
			{
				if (index!=null)
				{
					list[(int) index]=newValue;
				}
				else
				{
					index=list.Add(newValue);
				}
			}
			else if (context is IDictionary)
			{
				if (index==null)
				{
					throw new NotSupportedException("Null key is supported only for IList, but not for IDictionary");
				}
				((IDictionary) context)[index] = newValue;
			}
		}
	}
}